
import java.util.*;
import ast.*;

/* pretty-printer (using the visitor) */

class Pretty extends EmptyVisitor {

    private static void print(String s) { System.out.print(s); }
    private static void println() { System.out.println(); }
    private static void println(String s) { System.out.println(s); }
    private static int indent = 0;
    private static void newline() {
	println();
	for (int i = 0; i < indent; i++) print(" ");
    }

  public void visit(JmmFile n) {
      for (Iterator it = n.classes.iterator(); it.hasNext(); ) 
	  ((JmmClass)it.next()).accept(this);
      n.main.accept(this);
  }
  public void visit(JmmClass n) {
      print("class " + n.class_id);
      if (!n.class_inh.id_val.equals("Object"))
	  print(" inherits " + n.class_inh.id_val);
      print(" begin");
      indent = 2; newline();
      for (Iterator it = n.class_fields.iterator(); it.hasNext(); )
	  ((Field)it.next()).accept(this);
      println("end");
  }
  public void visit(Fattribute n) {
      print(n.attr_ty.ty_val + " ");
      for (Iterator it = n.attr_ids.iterator(); it.hasNext(); )
	  print(((Ident)it.next()).id_val + ", ");
      print(";"); newline ();
  }
  static void formals(VarList l) {
      for (Iterator it = l.iterator(); it.hasNext(); ) {
	  Var v = (Var)it.next();
	  print(v.var_ty.ty_val + " " + v.var_id.id_val + ", ");
      }
  }
  public void visit(Fconstructor n) {
      print(n.cstr_id.id_val + "(");
      formals(n.cstr_args);
      print(")"); indent += 2; newline ();
      n.cstr_body.accept(this);
      indent = 2; newline();
  }
  public void visit(Fmethod n) {
      print(n.meth_ty.ty_val + " " + n.meth_id.id_val + "(");
      formals(n.meth_args);
      print(")"); indent += 2; newline ();
      n.meth_body.accept(this);
      indent = 2; newline();
  }
  public void visit(Ethis n) { print("this"); }
  public void visit(Enull n) { print("null"); }
  public void visit(Econst_bool n) { print(String.valueOf(n.val)); }
  public void visit(Econst_int n) { print(String.valueOf(n.val)); }
  public void visit(Econst_string n) { print(n.val); }
  public void visit(Eident n) { print(n.val.id_val); }
  void binop(Expr e1, String op, Expr e2) {
      print("("); e1.accept(this); print(op); e2.accept(this); print(")");
  }
  public void visit(Eplus n) { binop(n.e1, "+", n.e2); }
  public void visit(Eminus n) { binop(n.e1, "-", n.e2); }
  public void visit(Emult n) { binop(n.e1, "*", n.e2); }
  public void visit(Ediv n) { binop(n.e1, "/", n.e2); }
  public void visit(Elt n) { binop(n.e1, "<", n.e2); }
  public void visit(Ele n) { binop(n.e1, "<=", n.e2); }
  public void visit(Egt n) { binop(n.e1, ">", n.e2); }
  public void visit(Ege n) { binop(n.e1, ">=", n.e2); }
  public void visit(Eeq n) { binop(n.e1, "=", n.e2); }
  public void visit(Eneq n) { binop(n.e1, "<>", n.e2); }
  public void visit(Eand n) { binop(n.e1, "and", n.e2); }
  public void visit(Eor n) { binop(n.e1, "or", n.e2); }
  public void visit(Eassign n) { binop(n.e1, ":=", n.e2); }
  public void visit(Eseq n) { 
      n.e1.accept(this); print(";"); newline(); n.e2.accept(this);
  }
  public void visit(Eneg n) {
      print("(-"); n.e1.accept(this); print(")");
  }
  public void visit(Enot n)  {
      print("(not "); n.e1.accept(this); print(")");
  }
    void args(ExprList l) {
	for (Iterator it = l.iterator(); it.hasNext(); ) {
	    ((Expr)it.next()).accept(this); 
	    print(", ");
	}
    }
  public void visit(Enew n) {
      print("(new " + n.f + "("); args(n.args); print("))");
  }
  public void visit(Eprimcall n) {
      print(n.f + "("); args(n.args); print(")");
  }
  public void visit(Efield n) {
      print("("); n.e.accept(this); print("." + n.f + ")"); 
  }
  public void visit(Emethcall n) {
      print("("); n.e.accept(this); print("." + n.f + "("); 
      args(n.args); print("))");
  }
  public void visit(Eif n) {
      print("(if "); n.e1.accept(this); print(" then");
      indent += 2; newline(); n.e2.accept(this); 
      indent -= 2; newline (); print(" else");
      indent += 2; newline (); n.e3.accept(this); print(")"); indent -= 2;
  }
  public void visit(Ewhile n) {
      print("(while "); n.e1.accept(this); print(" do");
      indent += 2; newline(); 
      n.e2.accept(this); print(")"); indent -= 2;
  }
  public void visit(Eletin n) {
      print("let " + n.id + " = "); n.e1.accept(this); print(" in");
      newline (); n.e2.accept(this);
  }
  public void visit(Enop n) { print("nop"); }

}
